<template>
    <div class="app-container">
      <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="100px">
        <el-form-item label="训练任务名称" prop="name">
          <el-input v-model="queryParams.name" placeholder="请输入训练任务名称" clearable @keyup.enter="handleQuery" />
        </el-form-item>
        <el-form-item label="源模型名称" prop="sourceModelName">
          <el-input v-model="queryParams.sourceModelName" placeholder="请输入源模型名称" clearable @keyup.enter="handleQuery" />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
          <el-button icon="Refresh" @click="resetQuery">重置</el-button>
        </el-form-item>
      </el-form>
  
      <el-row :gutter="10" class="mb8">
        <el-col :span="1.5">
          <el-button type="primary" plain icon="Plus" @click="handleAdd">新增训练任务</el-button>
        </el-col>
        <el-col :span="1.5">
          <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete"
            v-hasPermi="['model:train:remove']">删除</el-button>
        </el-col>
        <right-toolbar  @queryTable="getList"></right-toolbar>
      </el-row>
  
      <el-table v-loading="loading" :data="taskList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="任务ID" align="center" prop="id" width="80" />
        <el-table-column label="任务名称" align="center" prop="name" width="150" />
        <el-table-column label="源模型" align="center" prop="sourceModelName" width="150" />
        <el-table-column label="训练参数" align="center" prop="trainParams" width="200">
          <template #default="{row}">
            <el-tooltip effect="dark" :content="row.trainParams" placement="top">
              <span class="ellipsis-text">{{ row.trainParams }}</span>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column label="评价指标" align="center" prop="metrics" width="220">
          <template #default="{row}">
            <el-popover placement="top" trigger="hover" width="auto">
              <template #reference>
                <el-tag type="info">查看指标</el-tag>
              </template>
              <div v-if="row.metrics">
                <p v-for="(value, key) in JSON.parse(row.metrics)" :key="key">
                  <strong>{{ key }}:</strong> {{ value }}
                </p>
              </div>
              <div v-else>无评价指标</div>
            </el-popover>
          </template>
        </el-table-column>
        <el-table-column label="状态" align="center" prop="status" width="100">
          <template #default="{row}">
            <el-tag :type="statusTagType[row.status]">
              {{ statusText[row.status] || row.status }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="创建时间" align="center" prop="createTime" width="180" />
        <el-table-column label="操作" align="center" width="200" class-name="small-padding fixed-width">
          <template #default="{row}">
            <el-button link type="primary" icon="View" @click="handleView(row)" v-hasPermi="['model:train:query']">详情</el-button>
            <el-button link type="danger" icon="Delete" @click="handleDelete(row)" v-hasPermi="['model:train:remove']">删除</el-button>
            <el-button link type="success" icon="Download" @click="handleDownload(row)" 
              v-if="row.status === 'completed' && row.modelPath">下载模型</el-button>
          </template>
        </el-table-column>
      </el-table>
  
      <pagination
       :current-page="queryParams.pageNum"
       :page-size="queryParams.pageSize"
       @update:current-page="val => queryParams.pageNum = val"
       @update:page-size="val => queryParams.pageSize = val"
       />
      <!-- 添加或修改训练任务对话框 -->
      <el-dialog :title="title" v-model="open" width="800px" append-to-body>
        <el-form ref="trainFormRef" :model="form" :rules="rules" label-width="120px">
          <el-form-item label="任务名称" prop="name">
            <el-input v-model="form.name" placeholder="请输入训练任务名称" />
          </el-form-item>
          <el-form-item label="源模型" prop="sourceModelId">
            <el-select v-model="form.sourceModelId" placeholder="请选择源模型" filterable clearable @change="handleModelChange">
              <el-option
                v-for="item in modelOptions"
                :key="item.id"
                :label="item.name"
                :value="item.id"
                :disabled="item.status !== 'active'"
              />
            </el-select>
          </el-form-item>
          
          <el-form-item label="模型文件" prop="modelPath">
            <el-input v-model="selectedModel.modelPath" readonly placeholder="请先选择源模型" />
          </el-form-item>
          
          <el-form-item label="训练数据" prop="trainFile">
            <el-upload
              ref="uploadRef"
              class="upload-demo"
              action=""
              :limit="1"
              :auto-upload="false"
              :on-change="handleFileChange"
              :on-remove="handleFileRemove"
              accept=".xlsx,.xls"
            >
              <el-button type="primary">选择文件</el-button>
              <template #tip>
                <div class="el-upload__tip">请上传Excel格式的特征数据文件</div>
              </template>
            </el-upload>
          </el-form-item>
          
          <el-form-item label="迭代次数" prop="epochs">
            <el-input-number v-model="form.epochs" :min="1" :max="1000" controls-position="right" />
          </el-form-item>
          
          <el-form-item label="批处理大小" prop="batchSize">
            <el-input-number v-model="form.batchSize" :min="1" :max="1024" controls-position="right" />
          </el-form-item>
          
          <el-form-item label="学习率" prop="learningRate">
            <el-input-number v-model="form.learningRate" :min="0.0001" :max="1" :step="0.0001" controls-position="right" />
          </el-form-item>
          
          <el-form-item label="验证集比例" prop="valSplit">
            <el-slider v-model="form.valSplit" :min="0" :max="0.5" :step="0.01" show-input />
          </el-form-item>
          
          <el-form-item label="随机种子" prop="randomSeed">
            <el-input-number v-model="form.randomSeed" :min="0" :max="9999" controls-position="right" />
          </el-form-item>
        </el-form>
        
        <template #footer>
          <div class="dialog-footer">
            <el-button @click="cancel">取 消</el-button>
            <el-button type="primary" @click="submitForm" :loading="submitLoading">确 定</el-button>
          </div>
        </template>
      </el-dialog>
      
      <!-- 训练任务详情对话框 -->
      <el-dialog title="训练任务详情" v-model="detailOpen" width="800px" append-to-body>
        <el-descriptions :column="2" border>
          <el-descriptions-item label="任务ID">{{ detailData.id }}</el-descriptions-item>
          <el-descriptions-item label="任务名称">{{ detailData.name }}</el-descriptions-item>
          <el-descriptions-item label="源模型">{{ detailData.sourceModelName }}</el-descriptions-item>
          <el-descriptions-item label="状态">
            <el-tag :type="statusTagType[detailData.status]">
              {{ statusText[detailData.status] || detailData.status }}
            </el-tag>
          </el-descriptions-item>
          <el-descriptions-item label="创建时间">{{ detailData.createTime }}</el-descriptions-item>
          <el-descriptions-item label="完成时间">{{ detailData.endTime || '-' }}</el-descriptions-item>
          <el-descriptions-item label="训练参数" :span="2">
            <pre>{{ JSON.parse(detailData.trainParams || '{}') | prettyJson }}</pre>
          </el-descriptions-item>
          <el-descriptions-item label="评价指标" :span="2">
            <div v-if="detailData.metrics">
              <el-row :gutter="20">
                <el-col :span="6" v-for="(value, key) in JSON.parse(detailData.metrics)" :key="key">
                  <el-statistic :title="key" :value="value" />
                </el-col>
              </el-row>
            </div>
            <span v-else>-</span>
          </el-descriptions-item>
          <el-descriptions-item label="错误信息" :span="2">
            {{ detailData.errorMsg || '-' }}
          </el-descriptions-item>
          <el-descriptions-item label="模型路径" :span="2">
            {{ detailData.modelPath || '-' }}
          </el-descriptions-item>
        </el-descriptions>
      </el-dialog>
    </div>
  </template>
  
  <script setup>
  import { ref, reactive, onMounted } from 'vue'
 
  import { listTrainTask, getTrainTask, addTrainTask, updateTrainTask, deleteTrainTask, downloadModel } from '@/api/model/train'
  import { listSourceModel } from '@/api/model/source'
  
  const { proxy } = getCurrentInstance()
  
  const taskList = ref([])
  const loading = ref(true)
  const showSearch = ref(true)
  const ids = ref([])
  const single = ref(true)
  const multiple = ref(true)
  const total = ref(0)
  const title = ref('')
  const open = ref(false)
  const detailOpen = ref(false)
  const submitLoading = ref(false)
  
  const modelOptions = ref([])
  const selectedModel = ref({})
  const uploadRef = ref()
  const trainFile = ref(null)
  
  const statusText = {
    pending: '待训练',
    running: '训练中',
    completed: '已完成',
    failed: '训练失败'
  }
  
  const statusTagType = {
    pending: 'info',
    running: 'warning',
    completed: 'success',
    failed: 'danger'
  }

  
  const data = reactive({
    form: {},
   
    detailData: {},
    rules: {
      name: [
        { required: true, message: '任务名称不能为空', trigger: 'blur' }
      ],
      sourceModelId: [
        { required: true, message: '请选择源模型', trigger: 'change' }
      ],
      trainFile: [
        { required: true, message: '请上传训练数据文件', trigger: 'change' }
      ],
      epochs: [
        { required: true, message: '请输入迭代次数', trigger: 'blur' }
      ],
      batchSize: [
        { required: true, message: '请输入批处理大小', trigger: 'blur' }
      ],
      learningRate: [
        { required: true, message: '请输入学习率', trigger: 'blur' }
      ]
    }
  })
  
  const { form, queryParams, detailData, rules } = toRefs(data)
  
  /** 查询训练任务列表 */
  function getList() {
    loading.value = true
    listTrainTask(queryParams.value).then(response => {
      taskList.value = response.rows
      total.value = response.total
      loading.value = false
    })
  }
  
  /** 查询源模型列表 */
  function getModelOptions() {
    listSourceModel().then(response => {
      modelOptions.value = response.rows
    })
  }
  
  /** 重置查询表单 */
  function resetQuery() {
    proxy.resetForm('queryRef')
    handleQuery()
  }
  
  /** 搜索按钮操作 */
  function handleQuery() {
    queryParams.value.pageNum = 1
    getList()
  }
  
  /** 多选框选中数据 */
  function handleSelectionChange(selection) {
    ids.value = selection.map(item => item.id)
    single.value = selection.length !== 1
    multiple.value = !selection.length
  }
  
  /** 新增按钮操作 */
  function handleAdd() {
    reset()
    getModelOptions()
    open.value = true
    title.value = '添加训练任务'
  }
  
  /** 表单重置 */
  function reset() {
    form.value = {
      id: undefined,
      name: undefined,
      sourceModelId: undefined,
      trainFile: undefined,
      epochs: 10,
      batchSize: 32,
      learningRate: 0.001,
      valSplit: 0.2,
      randomSeed: 42
    }
    selectedModel.value = {}
    trainFile.value = null
    if (uploadRef.value) {
      uploadRef.value.clearFiles()
    }
    proxy.resetForm('trainFormRef')
  }
  
  /** 取消按钮 */
  function cancel() {
    open.value = false
    reset()
  }
  
  /** 提交表单 */
  function submitForm() {
    proxy.$refs['trainFormRef'].validate(valid => {
      if (valid) {
        if (!trainFile.value) {
          ElMessage.error('请上传训练数据文件')
          return
        }
        
        submitLoading.value = true
        
        const formData = new FormData()
        formData.append('file', trainFile.value.raw)
        formData.append('name', form.value.name)
        formData.append('sourceModelId', form.value.sourceModelId)
        formData.append('params', JSON.stringify({
          epochs: form.value.epochs,
          batchSize: form.value.batchSize,
          learningRate: form.value.learningRate,
          valSplit: form.value.valSplit,
          randomSeed: form.value.randomSeed
        }))
        
        addTrainTask(formData).then(response => {
          ElMessage.success('新增成功')
          open.value = false
          getList()
        }).finally(() => {
          submitLoading.value = false
        })
      }
    })
  }
  
  /** 删除按钮操作 */
  function handleDelete(row) {
    const taskIds = row.id || ids.value
    ElMessageBox.confirm('是否确认删除训练任务编号为"' + taskIds + '"的数据项?', '警告', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    }).then(() => {
      return deleteTrainTask(taskIds)
    }).then(() => {
      getList()
      ElMessage.success('删除成功')
    }).catch(() => {})
  }
  
  /** 查看详情按钮操作 */
  function handleView(row) {
    getTrainTask(row.id).then(response => {
      detailData.value = response.data
      detailOpen.value = true
    })
  }
  
  /** 下载模型按钮操作 */
  function handleDownload(row) {
    if (!row.modelPath) {
      ElMessage.error('没有可下载的模型文件')
      return
    }
    
    downloadModel(row.id).then(response => {
      const blob = new Blob([response], { type: 'application/octet-stream' })
      const link = document.createElement('a')
      link.href = URL.createObjectURL(blob)
      link.download = `${row.name}_model.pth`
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
    }).catch(error => {
      ElMessage.error('下载失败: ' + (error.message || '未知错误'))
    })
  }
  
  /** 源模型选择变化 */
  function handleModelChange(modelId) {
    if (modelId) {
      selectedModel.value = modelOptions.value.find(item => item.id === modelId) || {}
    } else {
      selectedModel.value = {}
    }
  }
  
  /** 文件上传变化 */
  function handleFileChange(file) {
    trainFile.value = file
  }
  
  /** 文件移除 */
  function handleFileRemove() {
    trainFile.value = null
  }
  
  onMounted(() => {
    getList()
  })
  </script>
  
  <style scoped>
  .ellipsis-text {
    display: inline-block;
    width: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  
  .upload-demo {
    width: 100%;
  }
  
  pre {
    margin: 0;
    padding: 10px;
    background-color: #f5f7fa;
    border-radius: 4px;
    white-space: pre-wrap;
    word-wrap: break-word;
  }
  </style>